package com.hm.health.View;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import androidx.annotation.Nullable;

import com.hm.health.R;

public class SleepTimeAxisView extends View {
    public static final String TAG = "SleepTimeAxisView";

    private Paint mFullPaint;
    private Paint mStrokPaint;
    private Paint mArcPaint;
    private Paint mLinePaint;
    private Paint mArcStrokePaint;
    private Context mContext;
    private int mMargin;
    private int mRowMargin;
    private int mStrokeWidth;
    private int mCornerWidth;
    private int mSleepData[];
    private int mDataLength;

    public SleepTimeAxisView(Context context) {
        super(context);
        init(context);
    }

    public SleepTimeAxisView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public SleepTimeAxisView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    public SleepTimeAxisView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context);
    }

    private void init(Context context) {
        mContext = context;
        mMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                        10, getResources().getDisplayMetrics());

        mRowMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                10, getResources().getDisplayMetrics());

        mStrokeWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                1, getResources().getDisplayMetrics());

        mCornerWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                4, getResources().getDisplayMetrics());
        initPaint();
    }

    public void setData(int[] data) {
        mSleepData = data;
        mDataLength = mSleepData.length;
    }

    private void initPaint() {
        mFullPaint = new Paint();
        mFullPaint.setAntiAlias(true);
        mFullPaint.setStyle(Paint.Style.FILL);
        mFullPaint.setColor(mContext.getResources().getColor(R.color.sleep_deep));

        mStrokPaint = new Paint();
        mStrokPaint.setAntiAlias(true);
        mStrokPaint.setStyle(Paint.Style.STROKE);
        mStrokPaint.setStrokeWidth(mStrokeWidth);
        mStrokPaint.setColor(mContext.getResources().getColor(R.color.sleep_deep));

        mArcPaint = new Paint();
        mArcPaint.setAntiAlias(true);
        mArcPaint.setStyle(Paint.Style.FILL);
        mArcPaint.setColor(mContext.getResources().getColor(R.color.white));


        mLinePaint = new Paint();
        mLinePaint.setAntiAlias(true);
        mLinePaint.setStyle(Paint.Style.STROKE);
        mLinePaint.setStrokeWidth(mStrokeWidth);
        mLinePaint.setColor(mContext.getResources().getColor(R.color.sleep_deep));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int width = getMeasuredWidth()- mMargin * 2;
        int height = getMeasuredHeight();

        int rowHeight = height / 4;
        int currentRectLeft = 0;
        int currentRectTop = 0;
        int currentRectRight = 0;
        int currentRectBottom = 0;
        int previousRectLeft = 0;
        int previousRectTop = 0;
        int previousRectRight = 0;
        int previousRectBottom = 0;
        boolean currentIsUp = false;
        boolean previousIsUp = false;
        boolean isFirstRect = false;
        boolean isLastRect = false;

        int previousColor = 0;
        int currentColor = 0;

        int currentData = 0;
        int previousData = 0;

        for (int i =0; i < mDataLength; i++) {
            currentData = mSleepData[i];
            if (currentData != 0 && currentData != 1 && currentData != 2 && currentData != 3) {
                continue;
            }
            currentData = 3 - currentData;

            if (i == 0) {
                currentRectLeft = mMargin;
                currentRectTop = currentData * rowHeight;
                currentRectBottom = currentRectTop + rowHeight - mRowMargin;
                previousData = currentData;
                isFirstRect = true;
            } else {
                if (previousData == currentData && i != mDataLength - 1) {
                    continue;
                } else {
                    if (i == mDataLength - 1) {
                        isLastRect = true;
                    }
                    currentIsUp = previousData < currentData ? false : true;
                    currentRectRight = mMargin + i * width / mDataLength;

                    // draw main rect.
                    if (previousData == 0) {
                        mFullPaint.setColor(mContext.getResources().getColor(R.color.sleep_wake));
                        mStrokPaint.setColor(mContext.getResources().getColor(R.color.sleep_wake_stroke));
                        currentColor = mContext.getResources().getColor(R.color.sleep_wake_stroke);
                    } else if (previousData == 1) {
                        mFullPaint.setColor(mContext.getResources().getColor(R.color.sleep_rem));
                        mStrokPaint.setColor(mContext.getResources().getColor(R.color.sleep_rem_stroke));
                        currentColor = mContext.getResources().getColor(R.color.sleep_rem_stroke);
                    } else if (previousData == 2) {
                        mFullPaint.setColor(mContext.getResources().getColor(R.color.sleep_light));
                        mStrokPaint.setColor(mContext.getResources().getColor(R.color.sleep_light_stroke));
                        currentColor = mContext.getResources().getColor(R.color.sleep_light_stroke);
                    } else if (previousData == 3) {
                        mFullPaint.setColor(mContext.getResources().getColor(R.color.sleep_deep));
                        mStrokPaint.setColor(mContext.getResources().getColor(R.color.sleep_deep_stroke));
                        currentColor = mContext.getResources().getColor(R.color.sleep_deep_stroke);
                    }

                    int currentsRectWidth = currentRectRight - currentRectLeft;
                    int cornerWidth = 0;
                    if (currentsRectWidth < mCornerWidth) {
                        cornerWidth = currentsRectWidth;
                    } else {
                        cornerWidth = mCornerWidth;
                    }

                    // draw current rect.
                    RectF rect = new RectF(currentRectLeft, currentRectTop, currentRectRight, currentRectBottom);
                    canvas.drawRoundRect(rect, cornerWidth, cornerWidth, mFullPaint);
                    canvas.drawRoundRect(rect, cornerWidth, cornerWidth,mStrokPaint);

                    if (!isFirstRect) {
                        // draw left rect
                        RectF rectF = new RectF();

                        if (previousIsUp) {
                            rectF.set(currentRectLeft, currentRectBottom - cornerWidth, currentRectLeft + cornerWidth, currentRectBottom + cornerWidth);
                        } else {
                            rectF.set(currentRectLeft, currentRectTop - cornerWidth, currentRectLeft + cornerWidth, currentRectTop + cornerWidth);
                        }
                        canvas.drawRect(rectF, mFullPaint);

                        // draw arc.
                        if (previousIsUp) {
                            rectF.set(currentRectLeft, currentRectBottom, currentRectLeft + 2 * cornerWidth, currentRectBottom + 2 * cornerWidth);
                            canvas.drawArc(rectF, 180, 90, true, mArcPaint);
                            canvas.drawArc(rectF, 180, 90, false, mStrokPaint);
                        } else {
                            rectF.set(currentRectLeft, currentRectTop - 2 * cornerWidth, currentRectLeft + 2 * cornerWidth, currentRectTop);
                            canvas.drawArc(rectF, 90, 90, true, mArcPaint);
                            canvas.drawArc(rectF, 90, 90, false, mStrokPaint);
                        }
                    }

                    if (!isLastRect) {
                        // draw right rect
                        RectF rectF = new RectF();

                        if (currentIsUp) {
                            rectF.set(currentRectRight - cornerWidth, currentRectTop - cornerWidth, currentRectRight, currentRectTop + cornerWidth);
                        } else {
                            rectF.set(currentRectRight - cornerWidth, currentRectBottom - cornerWidth, currentRectRight, currentRectBottom + cornerWidth);
                        }
                        canvas.drawRect(rectF, mFullPaint);

                        // draw arc.
                        if (currentIsUp) {
                            rectF.set(currentRectRight - 2 * cornerWidth, currentRectTop -  2 * cornerWidth, currentRectRight, currentRectTop);
                            canvas.drawArc(rectF, 0, 90, true, mArcPaint);
                            canvas.drawArc(rectF, 0, 90, false, mStrokPaint);
                        } else {
                            rectF.set(currentRectRight - 2 * cornerWidth, currentRectBottom, currentRectRight, currentRectBottom + 2 * cornerWidth);
                            canvas.drawArc(rectF, 270, 90, true, mArcPaint);
                            canvas.drawArc(rectF, 270, 90, false, mStrokPaint);
                        }
                    }

                    if (!isFirstRect) {
                        // draw left connector
                        if (previousIsUp) {
                            LinearGradient linearGradient = new LinearGradient(previousRectRight,
                                    previousRectTop + cornerWidth + 1,
                                    currentRectLeft,
                                    currentRectBottom  - cornerWidth - 1,
                                    previousColor,
                                    currentColor,
                                    Shader.TileMode.CLAMP
                            );
                            mLinePaint.setShader(linearGradient);
                            canvas.drawLine(previousRectRight, previousRectTop + cornerWidth + 2, currentRectLeft, currentRectBottom  - cornerWidth - 2, mLinePaint);
                        } else {
                            LinearGradient linearGradient = new LinearGradient(previousRectRight,
                                    previousRectBottom - cornerWidth - 1,
                                    currentRectLeft,
                                    currentRectTop  + cornerWidth + 1,
                                    previousColor,
                                    currentColor,
                                    Shader.TileMode.CLAMP
                            );
                            mLinePaint.setShader(linearGradient);
                            canvas.drawLine(previousRectRight, previousRectBottom - cornerWidth - 2, currentRectLeft, currentRectTop  + cornerWidth + 2, mLinePaint);
                        }
                    }

                    if (isFirstRect) {
                        isFirstRect = false;
                    }

                    // save status.
                    previousRectLeft = currentRectLeft;
                    previousRectTop = currentRectTop;
                    previousRectRight = currentRectRight;
                    previousRectBottom = currentRectBottom;
                    previousIsUp = currentIsUp;
                    previousData = currentData;
                    previousColor = currentColor;

                    currentRectLeft = currentRectRight;
                    currentRectTop = currentData * rowHeight;
                    currentRectBottom = currentRectTop + rowHeight  - mRowMargin;
                }
            }
        }
    }
}
